package com.speedchina.common.redis.conf;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.speedchina.common.redis.properties.ClusterPropertis;
import com.speedchina.common.redis.properties.SentinelProperties;
import com.speedchina.common.redis.properties.SingleProperties;
import com.speedchina.common.redis.serializer.StringKeyRedisSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.*;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Winter
 */
@Slf4j
@Configuration
public class RedisConfig {

    /**
     * 单节点配置
     */
    @Autowired
    SingleProperties singleProperties;
    /**
     * 集群配置
     */
    @Autowired
    ClusterPropertis clusterPropertis;
    /**
     * 哨兵模式
     */
    @Autowired
    SentinelProperties sentinelProperties;

    /**
     * JedisPool
     * @return
     */
    @Bean("JedisPool")
    public JedisPoolConfig jedisPool() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(singleProperties.getMaxIdle());
        jedisPoolConfig.setMaxWaitMillis(singleProperties.getMaxWait());
        jedisPoolConfig.setMaxTotal(singleProperties.getMaxActive());
        jedisPoolConfig.setMinIdle(singleProperties.getMinIdle());
        return jedisPoolConfig;
    }
    /**
     * 单节点配置
     */
    @Bean(name = "RedisConnectionFactorySingle")
    public RedisConnectionFactory initRedisSingleFactory(){
        JedisConnectionFactory connectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration());
        return connectionFactory;
    }
    /**
     * 哨兵模式
     */
    public RedisConnectionFactory initRedisSentinelnFactory(){
        JedisConnectionFactory connectionFactory = new JedisConnectionFactory(redisSentinelConfiguration(),jedisPool());
        return connectionFactory;
    }
    /**
     * 集群配置
     */
    public RedisConnectionFactory redisConnectionFactoryCluster(JedisPoolConfig jedisPool,
                                                                RedisClusterConfiguration jedisConfig) {
        JedisConnectionFactory factory = new JedisConnectionFactory(jedisConfig, jedisPool);
        factory.afterPropertiesSet();
        return factory;
    }
    /**
     * 单节点配置
     */
    public RedisStandaloneConfiguration redisStandaloneConfiguration(){
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
        configuration.setDatabase(singleProperties.getDatabase());
        configuration.setHostName(singleProperties.getHost());
        configuration.setPassword(singleProperties.getPassword());
        configuration.setPort(singleProperties.getPort());
        return configuration;
    }
    /**
     * 哨兵模式
     */
    public RedisSentinelConfiguration redisSentinelConfiguration(){
        RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();
        redisSentinelConfiguration.setMaster(sentinelProperties.getMaster());
        redisSentinelConfiguration.setDatabase(singleProperties.getDatabase());
        redisSentinelConfiguration.setPassword(singleProperties.getPassword());
        String nodes = sentinelProperties.getNodes();
        String[] sub = nodes.split(",");
        List<RedisNode> nodeList = new ArrayList<RedisNode>(sub.length);
        String[] tmp;
        for (String s : sub) {
            tmp = s.split(":");
            // fixme 先不考虑异常配置的case
            nodeList.add(new RedisNode(tmp[0], Integer.valueOf(tmp[1])));
        }
        redisSentinelConfiguration.setSentinels(nodeList);
        redisSentinelConfiguration.setSentinelPassword(singleProperties.getPassword());
        return redisSentinelConfiguration;
    }
    /**
     * 集群配置
     */
    @Bean
    public RedisClusterConfiguration redisClusterConfiguration() {
        RedisClusterConfiguration config = new RedisClusterConfiguration();
        String nodes = clusterPropertis.getNodes();
        if(nodes==null||nodes.length()<20){
            return config;
        }
        String[] sub = nodes.split(",");
        List<RedisNode> nodeList = new ArrayList<RedisNode>(sub.length);
        String[] tmp;
        for (String s : sub) {
            tmp = s.split(":");
            // fixme 先不考虑异常配置的case
            nodeList.add(new RedisNode(tmp[0], Integer.valueOf(tmp[1])));
        }

        config.setClusterNodes(nodeList);
        config.setMaxRedirects(clusterPropertis.getMaxRedirects());
        config.setPassword(RedisPassword.of(singleProperties.getPassword()));
        return config;
    }
    @Bean(name = "redisTemplate")
    public RedisTemplate<String,Object> redisTemplate(){
        String mode = singleProperties.getMode();
        log.info(mode);
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        if("single".equals(mode)){
            redisTemplate.setConnectionFactory(initRedisSingleFactory());
        }else if("cluster".equals(mode)){
            redisTemplate.setConnectionFactory(redisConnectionFactoryCluster(jedisPool(),redisClusterConfiguration()));
        }else {
            redisTemplate.setConnectionFactory(initRedisSentinelnFactory());
        }
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
//        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        StringKeyRedisSerializer stringKeyRedisSerializer = new StringKeyRedisSerializer(singleProperties.getKeyPrefix());
        // key采用String的序列化方式
        redisTemplate.setKeySerializer(stringKeyRedisSerializer);
        // hash的key也采用String的序列化方式
        redisTemplate.setHashKeySerializer(stringKeyRedisSerializer);
        // value序列化方式采用jackson
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
